package etf.hibernate;

import java.util.List;
import java.util.Random;

import etf.library.*;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

public class IntermediateHibernate{
	SessionFactory sessions;
	Session session;
	Transaction tx;

	public IntermediateHibernate() {
		// Create SessionFactory and Session object
		sessions = new Configuration().configure().buildSessionFactory();
		session = sessions.openSession();
		tx = null;
	}
	public long insert(int brojSlogova) {
		long elapsedTime = 0;
		try {
			tx = session.beginTransaction();
			long startTime = System.currentTimeMillis();
			for (int i = 0; i < brojSlogova; i++) {
				Address address = new Address("Splitska" + i,i, "Sarajevo", i, "BiH");
				Employee emp = new Employee("John_"+i,"Doe_"+i,30,1500,address);
				session.save(emp);
				if (i%1000==0) {
					session.flush();
					session.clear();
				}
			}
			tx.commit();
			long stopTime = System.currentTimeMillis();
			elapsedTime = stopTime - startTime;

			tx = null;
		} catch (HibernateException e) {
			if (tx != null)
				tx.rollback();
			e.printStackTrace();
		}
		return elapsedTime;
	}
	
	public long query(int brojSlogova){
		String hqlQuery = "from Employee as c  where  c.address.houseNumber = :p";
		return queryUtil(brojSlogova, hqlQuery);
	}
	
	public long indexedQuery(int brojSlogova){
		String hqlQuery = "select c from Employee as c join c.address as a where a.zipPostCode = :p";
		return queryUtil(brojSlogova, hqlQuery);
	}
	
	private long queryUtil(int size, String hqlQuery){
		long elapsedTime = 0;
		double suma = 0;
		try {

			for (int i = 0; i < 4; i++) {
				long startTime = System.currentTimeMillis();
				Query query = session.createQuery(hqlQuery);
				query.setInteger("p", getRandom(size));
				List<Employee> employeeResult = query.list();
				if (employeeResult.size() > 0) {
					Employee emp = (Employee) employeeResult.get(0);
					System.out.println(emp.getFirstName());
				}
				long stopTime = System.currentTimeMillis();
				elapsedTime = stopTime - startTime;
				suma +=elapsedTime;
			}
			suma = suma/4;
		} catch (HibernateException e) {
			e.printStackTrace();
		}		
		return (long) suma;
	}
	
	public long update(int size){
		long elapsedTime = 0;
		String hqlQuery = "select c from Employee as c join c.address as a where a.zipPostCode = :p";
		try {
			tx = session.beginTransaction();
			Query query = session.createQuery(hqlQuery);
			long startTime = System.currentTimeMillis();
			
			query.setInteger("p", getRandom(size));
			List<Employee> employeeResult = query.list();
			if (employeeResult.size()>0){
				Employee emp = (Employee) employeeResult.get(0);		
				emp.setFirstName("New_name");
				session.save(emp);
			}
			tx.commit();
			long stopTime = System.currentTimeMillis();
			elapsedTime = stopTime - startTime;

			tx = null;
		} catch (HibernateException e) {
			if (tx != null)
				tx.rollback();
			e.printStackTrace();
		}		
		
		return elapsedTime;
	}
	
	public long delete(int size){
		String hqlDelete = "from Employee as e where address.houseNumber =:p";
		return deleteUtil(size, hqlDelete);
	}
	
	public long indexedDelete(int size){
		String hqlDelete = "from Employee as e where e.address.zipPostCode =:p";
		return deleteUtil(size, hqlDelete);
	}
	
	private long deleteUtil(int size, String hqlDelete) {
		long elapsedTime = 0;
		double suma = 0;
		try {
			
			for (int i = 0; i < 4; i++) {
				long startTime = System.currentTimeMillis();
				tx = session.beginTransaction();
				Query deleteQuery = session.createQuery(hqlDelete);
				deleteQuery.setInteger("p", getRandom(size));
				List<Employee> employeeResult = deleteQuery.list();
				if (employeeResult.size() > 0) {
					session.delete(employeeResult.get(0));
				}
				tx.commit();
				long stopTime = System.currentTimeMillis();
				elapsedTime = stopTime - startTime;
				suma += elapsedTime;
			}
			suma = suma/4;
			tx = null;
		} catch (HibernateException e) {
			if (tx != null)
				tx.rollback();
			e.printStackTrace();
		}		
		
		return (long) suma;
	}
	
	// -------------------------------------------------------------------------------------------
	//											1 to N
	//-------------------------------------------------------------------------------------------
	
	public long insert_1_to_N(int brojSlogova) {
		long elapsedTime = 0;
		try {
			long startTime = System.currentTimeMillis();
			tx = session.beginTransaction();
			Category cat = new Category("Drama");
			
			for (int i = 0; i < brojSlogova/100; i++) {
				Author author = new Author("Peter_"+i, "Lacko_" +i, "Male", i);
				for (int j = 0; j < 100; j++) {
					Book book = new Book("Book_" + j, i*100 + j, cat, author);
					author.addBook(book);
				}
				session.save(author);
				if (i%1000==0) {
					session.flush();
					session.clear();
				}
			}
			tx.commit();
			long stopTime = System.currentTimeMillis();
			elapsedTime = stopTime - startTime;

			tx = null;
		} catch (HibernateException e) {
			if (tx != null)
				tx.rollback();
			e.printStackTrace();
		}
		return elapsedTime;
	}
	
	public long query_1_to_N(int size){
		long elapsedTime = 0;
		String hqlQuery = "select a from Author as a join a.books as b where b.year = :p";
		try {			
			
			long startTime = System.currentTimeMillis();
			Query query = session.createQuery(hqlQuery);
			query.setInteger("p", getRandom(size));

			List<Author> authorResult = query.list();
			if (authorResult.size()>0){
				Author a =  authorResult.get(0);
				System.out.println("hib:" + a.getFirstName());
			}
			long stopTime = System.currentTimeMillis();
			elapsedTime = stopTime - startTime;

		} catch (HibernateException e) {

			e.printStackTrace();
		}		
		
		return elapsedTime;
	}
	
	public long update_1_to_N(int size){
		long elapsedTime = 0;
		String hqlQuery = "select a from Author as a join a.books as b where b.year = :p";
		try {
			
			
			long startTime = System.currentTimeMillis();
			tx = session.beginTransaction();
			Query query = session.createQuery(hqlQuery);
			query.setInteger("p", getRandom(size));

			List<Author> authorResult = query.list();
			if (authorResult.size()>0){
				Author a =  authorResult.get(0);
				a.setFirstName("New_name");
				session.save(a);
				System.out.println("hib:" + a.getFirstName());
			}
			tx.commit();
			long stopTime = System.currentTimeMillis();
			elapsedTime = stopTime - startTime;
		} catch (HibernateException e) {
			e.printStackTrace();
		}		
		
		return elapsedTime;
	}
	
	public long delete_1_to_N(int size){
		long elapsedTime = 0;
		String hqlQuery = "select a from Author as a join a.books as b where b.year = :p";
		try {
			
			long startTime = System.currentTimeMillis();
			tx = session.beginTransaction();
			Query query = session.createQuery(hqlQuery);
			query.setInteger("p", getRandom(size));

			List<Author> authorResult = query.list();
			if (authorResult.size()>0){
				Author a =  authorResult.get(0);
				session.delete(a);
			}
			tx.commit();
			long stopTime = System.currentTimeMillis();
			elapsedTime = stopTime - startTime;
		} catch (HibernateException e) {
			e.printStackTrace();
		}		
		
		return elapsedTime;
	}
	
	public long insert_N_to_N(int size){
		long elapsedTime = 0;
		try {
			tx = session.beginTransaction();
			long startTime = System.currentTimeMillis();
			Author author = new Author("Peter", "Lacko", "Male", 44);
			Category cat = new Category("Drama");
			
			for (int j = 0; j < size / 100; j++) {
				Member member = new Member("Mark_"+j, "Twain_"+j, j, "gmail");
				for (int i = 0; i < 100; i++) {
					int temp = j*100+i;
					Book book = new Book("Book_"+temp, i, cat, author);
					member.rentABook(book);
					book.addRenter(member);
				}
				session.save(member);
				if (j%1000==0) {
					session.flush();
					session.clear();
				}
			}
			tx.commit();
			long stopTime = System.currentTimeMillis();
			elapsedTime = stopTime - startTime;
			tx = null;
		} catch (HibernateException e) {
			if (tx != null)
				tx.rollback();
			e.printStackTrace();
		}
		return elapsedTime;
	}

	public long query_N_to_N(int size){
		long elapsedTime = 0;
		String hqlQuery = "select m from Member as m join m.rentedBooks as b where b.year = :p";
		try {
			tx = session.beginTransaction();
			
			Query query = session.createQuery(hqlQuery);
			long startTime = System.currentTimeMillis();
				query.setInteger("p", getRandom(100));

				List<Member> memberResult = query.list();
				if (memberResult.size()>0){
					Member m =  memberResult.get(0);
					System.out.println("hib:" + m.getFirstName());
				}
			long stopTime = System.currentTimeMillis();
			elapsedTime = stopTime - startTime;

			tx = null;
		} catch (HibernateException e) {
			if (tx != null)
				tx.rollback();
			e.printStackTrace();
		}		
		
		return elapsedTime;
	}
	
	public long update_N_to_N(int size){
		long elapsedTime = 0;
		String hqlQuery = "select m from Member as m join m.rentedBooks as b where b.year = :p";
		try {
			
			long startTime = System.currentTimeMillis();
			
			tx = session.beginTransaction();
			Query query = session.createQuery(hqlQuery);
			query.setInteger("p", getRandom(100));
			List<Member> memberResult = query.list();
			if(memberResult.size()>0){
				Member m =  memberResult.get(0);
				m.setFirstName("New_name");
				session.save(m);
				System.out.println("hib:" + m.getFirstName());
			}
			tx.commit();
			long stopTime = System.currentTimeMillis();
			elapsedTime = stopTime - startTime;
			tx = null;
		} catch (HibernateException e) {
			if (tx != null)
				tx.rollback();
			e.printStackTrace();
		}		
		
		return elapsedTime;
	}

	public long delete_N_to_N(int size){
		long elapsedTime = 0;
		String hqlQuery = "select m from Member as m join m.rentedBooks as b where b.title = :p";
		try {
			
			long startTime = System.currentTimeMillis();
			tx = session.beginTransaction();
			String bookTitle = "Book_"+getRandom(size);
			Query query = session.createQuery(hqlQuery);
			query.setString("p", bookTitle);
			List<Member> memberResult = query.list();
			if(memberResult.size()>0){
				Member m =  memberResult.get(0);
				Book b = m.returnBookByTitle(bookTitle);
				m.returnARentedBook(b);
				session.delete(b);
				session.save(m);
			}
			tx.commit();
			long stopTime = System.currentTimeMillis();
			elapsedTime = stopTime - startTime;
			tx = null;
		} catch (HibernateException e) {
			if (tx != null)
				tx.rollback();
			e.printStackTrace();
		}		
		
		return elapsedTime;
	}
	
	public void deleteFrom(String className){
		try {
			tx = session.beginTransaction();
			String hql = "delete from " + className;
			Query query = session.createQuery(hql);
			query.executeUpdate();
			tx.commit();
			tx = null;
		} catch (HibernateException e) {
			if (tx != null)
				tx.rollback();
			e.printStackTrace();
		}		
	}
	
	
	public void clear_1_on_1(){
		deleteFrom("Employee");
		deleteFrom("Address");
	}
	
	public void clear_1_on_N(){
		deleteFrom("Book");
		deleteFrom("Author");
	}
	
	public void clear_N_on_N(){
		deleteFrom("Book");
		deleteFrom("Member");
	}
	
	private int getRandom(int max){
		Random r = new Random();
        return r.nextInt(max); 
	}
}
